// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//
//   Remoting terminator sinks for sink chains along a remoting call. 
//   There is only one static instance of each of these exposed through 
//   the MessageSink property.
// 
namespace System.Runtime.Remoting.Messaging {

    using System;
    using System.Threading; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Channels; 
    using System.Runtime.Remoting.Contexts;
    using System.Collections; 
    using System.Globalization;
   //   Methods shared by all terminator sinks.
   //
    [Serializable] 
    internal class InternalSink
    { 
        /* 
         *  Checks the replySink param for NULL and type.
         *  If the param is good, it returns NULL. 
         *  Else it returns a Message with the relevant exception.
         */
        [System.Security.SecurityCritical]  // auto-generated
        internal static IMessage ValidateMessage(IMessage reqMsg) 
        {
            IMessage retMsg = null; 
            if (reqMsg == null) 
            {
                retMsg = new ReturnMessage( new ArgumentNullException("reqMsg"), null); 
            }
            return retMsg;
        }
 
        /*
         *  This check is performed only for client & server context 
         *  terminator sinks and only on the Async path. 
         *
         */ 
        [System.Security.SecurityCritical]  // auto-generated
        internal static IMessage DisallowAsyncActivation(IMessage reqMsg)
        {
            // < 

            if (reqMsg is IConstructionCallMessage) 
            { 

                return new ReturnMessage(new RemotingException(Environment.GetResourceString("Remoting_Activation_AsyncUnsupported")), 
                                         null /*reqMsg*/ );
            }
            return null;
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static Identity GetIdentity(IMessage reqMsg) 
        {
            Identity id = null; 

            if (reqMsg is IInternalMessage)
            {
                id = ((IInternalMessage) reqMsg).IdentityObject; 
            }
            else if (reqMsg is InternalMessageWrapper) 
            { 
                id = (Identity)((InternalMessageWrapper)reqMsg).GetIdentityObject();
            } 

            // Try the slow path if the identity has not been obtained yet
            if(null == id)
            { 
                String objURI = GetURI(reqMsg);
 
                id = IdentityHolder.ResolveIdentity(objURI); 

                // An object could get disconnected on another thread while a call is in progress 
                if(id == null)
                {
                    throw new ArgumentException(Environment.GetResourceString("Remoting_ServerObjectNotFound", objURI));
                } 
            }
 
            return id; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static ServerIdentity GetServerIdentity(IMessage reqMsg)
        {
            ServerIdentity srvID = null; 
            bool bOurMsg = false;
            String objURI = null; 
 
            IInternalMessage iim = reqMsg as IInternalMessage;
            if (iim != null) 
            {
                Message.DebugOut("GetServerIdentity.ServerIdentity from IInternalMessage\n");
                srvID = ((IInternalMessage) reqMsg).ServerIdentityObject;
                bOurMsg = true; 
            }
            else if (reqMsg is InternalMessageWrapper) 
            { 
                srvID = (ServerIdentity)((InternalMessageWrapper)reqMsg).GetServerIdentityObject();
            } 

            // Try the slow path if the identity has not been obtained yet
            if(null == srvID)
            { 
                Message.DebugOut("GetServerIdentity.ServerIdentity from IMethodCallMessage\n");
                objURI = GetURI(reqMsg); 
                Identity id = 
                    IdentityHolder.ResolveIdentity(objURI);
                if(id is ServerIdentity) 
                {
                    srvID = (ServerIdentity)id;

                    // Cache the serverIdentity in the message 
                    if (bOurMsg)
                    { 
                        iim.ServerIdentityObject = srvID; 
                    }
                } 
            }

            return srvID;
        } 

        // Retrieve the URI either via a method call or through 
        // a dictionary property. 
        [System.Security.SecurityCritical]  // auto-generated
        internal static String GetURI(IMessage msg) 
        {
            String uri = null;

            IMethodMessage mm = msg as IMethodMessage; 
            if (mm != null)
            { 
                uri = mm.Uri; 
            }
            else 
            {
                IDictionary prop = msg.Properties;
                if(null != prop)
                { 
                    uri = (String)prop["__Uri"];
                } 
            } 

            return uri; 
        }
    }

 
   //
   // Terminator sink for server envoy message sink chain. This delegates 
   // to the client context chain for the call. 
   //
 
    /* package scope */
    [Serializable]
    internal class EnvoyTerminatorSink : InternalSink, IMessageSink
    { 
        private static EnvoyTerminatorSink messageSink;
        private static Object staticSyncObject = new Object(); 
 
        internal static IMessageSink MessageSink
        { 
            get
            {
                if (messageSink == null)
                { 
                    EnvoyTerminatorSink tmpSink = new EnvoyTerminatorSink();
                    lock(staticSyncObject) 
                    { 
                        if (messageSink == null)
                        { 
                            messageSink = tmpSink;
                        }
                    }
                } 
                return messageSink;
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg)
        {
            Message.DebugOut("---------------------------Envoy Chain Terminator: SyncProcessMessage");
            IMessage errMsg = ValidateMessage(reqMsg); 
            if (errMsg != null)
            { 
                return errMsg; 
            }
            // Validate returns null if the reqMsg is okay! 
            return Thread.CurrentContext.GetClientContextChain().SyncProcessMessage(reqMsg);
        }

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        { 
            Message.DebugOut("---------------------------Envoy Chain Terminator: AsyncProcessMessage"); 
            IMessageCtrl msgCtrl = null;
            IMessage errMsg = ValidateMessage(reqMsg); 

            if (errMsg != null)
            {
                // Notify replySink of error if we can 
                // <
 
                if (replySink != null) 
                {
                    replySink.SyncProcessMessage(errMsg); 
                }
            }
            else
            { 
                msgCtrl = Thread.CurrentContext.GetClientContextChain().AsyncProcessMessage(reqMsg, replySink);
            } 
            return msgCtrl; 
        }
 
        public IMessageSink NextSink
        {
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                // We are the terminal sink of this chain 
                return null; 
            }
        } 

    }

 
   //
   // Terminator sink for client context message sink chain. This delegates 
   // to the appropriate channel sink for the call. 
   //
   // 

    /* package scope */
    internal class ClientContextTerminatorSink : InternalSink, IMessageSink
    { 
        private static ClientContextTerminatorSink messageSink;
        private static Object staticSyncObject = new Object(); 
 
        internal static IMessageSink MessageSink
        { 
            get
            {
                if (messageSink == null)
                { 
                    ClientContextTerminatorSink tmpSink = new ClientContextTerminatorSink();
                    lock(staticSyncObject) 
                    { 
                        if (messageSink == null)
                        { 
                            messageSink = tmpSink;
                        }
                    }
                } 
                return messageSink;
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static Object SyncProcessMessageCallback(Object[] args)
        {
            IMessage        reqMsg      = (IMessage) args[0];
            IMessageSink    channelSink = (IMessageSink) args[1]; 

            return channelSink.SyncProcessMessage(reqMsg); 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg)
        {
            Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: SyncProcessMsg");
            IMessage errMsg = ValidateMessage(reqMsg); 

            if (errMsg != null) 
            { 
                return errMsg;
            } 

            Context ctx = Thread.CurrentContext;

            bool bHasDynamicSinks = 
                ctx.NotifyDynamicSinks(reqMsg,
                        true,   // bCliSide 
                        true,   // bStart 
                        false,  // bAsync
                        true);  // bNotifyGlobals 

            IMessage replyMsg;
            if (reqMsg is IConstructionCallMessage)
            { 
                errMsg = ctx.NotifyActivatorProperties(
                                reqMsg, 
                                false /*bServerSide*/); 
                if (errMsg != null)
                { 
                    return errMsg;
                }

                replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate( 
                                (IConstructionCallMessage)reqMsg);
                BCLDebug.Assert(replyMsg is IConstructionReturnMessage,"bad ctorRetMsg"); 
                errMsg = ctx.NotifyActivatorProperties( 
                                replyMsg,
                                false /*bServerSide*/); 
                if (errMsg != null)
                {
                    return errMsg;
                } 
            }
            else 
            { 
                replyMsg = null;
                ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend); 

                Object[] args = new Object[] { null, null };

                IMessageSink channelSink = GetChannelSink(reqMsg); 

                // Forward call to the channel. 
                args[0] = reqMsg; 
                args[1] = channelSink;
 
                InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback);

                // Move to default context unless we are going through
                // the cross-context channel 
                if (channelSink != CrossContextChannel.MessageSink)
                { 
                    replyMsg = (IMessage) Thread.CurrentThread.InternalCrossContextCallback(Context.DefaultContext, xctxDel, args); 
                }
                else 
                {
                    replyMsg = (IMessage) xctxDel(args);
                }
 
                ChannelServices.NotifyProfiler(replyMsg, RemotingProfilerEvent.ClientReceive);
            } 
 

            if (bHasDynamicSinks) 
            {
                ctx.NotifyDynamicSinks(reqMsg,
                                   true,   // bCliSide
                                   false,  // bStart 
                                   false,  // bAsync
                                   true);  // bNotifyGlobals 
            } 

            return replyMsg; 
        }

        [System.Security.SecurityCritical]  // auto-generated
        internal static Object AsyncProcessMessageCallback(Object[] args) 
        {
            IMessage     reqMsg         = (IMessage) args[0]; 
            IMessageSink replySink      = (IMessageSink) args[1]; 
            IMessageSink channelSink    = (IMessageSink) args[2];
 
            return channelSink.AsyncProcessMessage(reqMsg, replySink);
        }

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        { 
            Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: AsyncProcessMsg"); 
            IMessage errMsg = ValidateMessage(reqMsg);
            IMessageCtrl msgCtrl=null; 
            if (errMsg == null)
            {
                errMsg = DisallowAsyncActivation(reqMsg);
            } 

            if (errMsg != null) 
            { 
                if (replySink != null)
                { 
                    replySink.SyncProcessMessage(errMsg);
                }
            }
            else 
            {
                // If active, notify the profiler that an asynchronous remoting call is being made. 
                if (RemotingServices.CORProfilerTrackRemotingAsync()) 
                {
                    Guid g; 

                    RemotingServices.CORProfilerRemotingClientSendingMessage(out g, true);

                    if (RemotingServices.CORProfilerTrackRemotingCookie()) 
                        reqMsg.Properties["CORProfilerCookie"] = g;
 
                    // Only wrap the replySink if the call wants a reply 
                    if (replySink != null)
                    { 
                        // Now wrap the reply sink in our own so that we can notify the profiler of
                        // when the reply is received.  Upon invocation, it will notify the profiler
                        // then pass control on to the replySink passed in above.
                        IMessageSink profSink = new ClientAsyncReplyTerminatorSink(replySink); 

                        // Replace the reply sink with our own 
                        replySink = profSink; 
                    }
                } 

                Context cliCtx = Thread.CurrentContext;

                // Notify dynamic sinks that an Async call started 
                cliCtx.NotifyDynamicSinks(
                        reqMsg, 
                        true,   // bCliSide 
                        true,   // bStart
                        true,   // bAsync 
                        true);  // bNotifyGlobals

                // Intercept the async reply to force the thread back
                // into the client-context before it executes further 
                // and to notify dynamic sinks
                if (replySink != null) 
                { 
                    replySink = new AsyncReplySink(replySink, cliCtx);
                } 

                Object[]  args = new Object[] { null, null, null };
                InternalCrossContextDelegate    xctxDel = new InternalCrossContextDelegate(AsyncProcessMessageCallback);
 
                IMessageSink channelSink = GetChannelSink(reqMsg);
 
                // Forward call to the channel. 
                args[0] = reqMsg;
                args[1] = replySink; 
                args[2] = channelSink;

                // Move to default context unless we are going through
                // the cross-context channel 
                if (channelSink != CrossContextChannel.MessageSink)
                { 
                    msgCtrl = (IMessageCtrl) Thread.CurrentThread.InternalCrossContextCallback(Context.DefaultContext, xctxDel, args); 
                }
                else 
                {
                    msgCtrl = (IMessageCtrl) xctxDel(args);
                }
            } 
            return msgCtrl;
        } 
 
        public IMessageSink NextSink
        { 
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                // We are the terminal sink of this chain 
                return null;
            } 
        } 

        // Find the next chain (or channel) sink to delegate to. 
        [System.Security.SecurityCritical]  // auto-generated
        private IMessageSink GetChannelSink(IMessage reqMsg)
        {
            Identity id = GetIdentity(reqMsg); 
            return id.ChannelSink;
        } 
    } 

    internal class AsyncReplySink : IMessageSink 
        {

            IMessageSink _replySink;// original reply sink that we are wrapping
            Context _cliCtx;        // the context this call emerged from 

            internal AsyncReplySink(IMessageSink replySink, Context cliCtx) 
            { 
                _replySink = replySink;
                _cliCtx = cliCtx; 
            }

            [System.Security.SecurityCritical]  // auto-generated
            internal static Object SyncProcessMessageCallback(Object[] args) 
            {
                IMessage        reqMsg      = (IMessage) args[0]; 
                IMessageSink    replySink   = (IMessageSink) args[1]; 

                // Call the dynamic sinks to notify that the async call 
                // has completed
                Thread.CurrentContext.NotifyDynamicSinks(
                    reqMsg, // this is the async reply
                    true,   // bCliSide 
                    false,  // bStart
                    true,   // bAsync 
                    true);  // bNotifyGlobals 

                // call the original reply sink now that we have moved 
                // to the correct client context
                return replySink.SyncProcessMessage(reqMsg);
            }
 
            [System.Security.SecurityCritical]  // auto-generated
            public virtual IMessage SyncProcessMessage(IMessage reqMsg) 
            { 
                // we just switch back to the old context before calling
                // the next replySink 
                IMessage retMsg = null;
                if (_replySink != null)
                {
                    Object[] args = new Object[] { reqMsg, _replySink }; 
                    InternalCrossContextDelegate    xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback);
 
                    retMsg = (IMessage) Thread.CurrentThread.InternalCrossContextCallback(_cliCtx, xctxDel, args); 
                }
                return retMsg; 
            }

            [System.Security.SecurityCritical]  // auto-generated
            public virtual IMessageCtrl AsyncProcessMessage( 
                IMessage reqMsg, IMessageSink replySink)
            { 
                throw new NotSupportedException(); 
            }
 
            public IMessageSink NextSink
            {
                [System.Security.SecurityCritical]  // auto-generated
                get 
                {
                    return _replySink; 
                } 
            }
        } 



 
   //
   // Terminator sink for server context message sink chain. This delegates 
   // to the appropriate object sink chain for the call. 
   //
   // 

    /* package scope */
    [Serializable]
    internal class ServerContextTerminatorSink : InternalSink, IMessageSink 
    {
        private static ServerContextTerminatorSink messageSink; 
        private static Object staticSyncObject = new Object(); 

        internal static IMessageSink MessageSink 
        {
            get
            {
                if (messageSink == null) 
                {
                    ServerContextTerminatorSink tmpSink = new ServerContextTerminatorSink(); 
                    lock(staticSyncObject) 
                    {
                        if (messageSink == null) 
                        {
                            messageSink = tmpSink;
                        }
                    } 
                }
                return messageSink; 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg)
        {
            Message.DebugOut("+++++++++++++++++++++++++ SrvCtxTerminator: SyncProcessMsg"); 
            IMessage errMsg = ValidateMessage(reqMsg);
            if (errMsg != null) 
            { 
                return errMsg;
            } 


            Context ctx = Thread.CurrentContext;
            IMessage replyMsg; 
            if (reqMsg is IConstructionCallMessage)
            { 
                errMsg = ctx.NotifyActivatorProperties( 
                                reqMsg,
                                true /*bServerSide*/); 
                if (errMsg != null)
                {
                    return errMsg;
                } 

                replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate((IConstructionCallMessage)reqMsg); 
                BCLDebug.Assert(replyMsg is IConstructionReturnMessage,"bad ctorRetMsg"); 
                errMsg = ctx.NotifyActivatorProperties(
                                replyMsg, 
                                true /*bServerSide*/);
                if (errMsg != null)
                {
                    return errMsg; 
                }
            } 
            else 
            {
                // Pass call on to the server object specific chain 
                MarshalByRefObject obj = null;
                try{
                    replyMsg = GetObjectChain(reqMsg, out obj).SyncProcessMessage(reqMsg);
                } 
                finally {
                    IDisposable iDis = null; 
                    if (obj != null && ((iDis=(obj as IDisposable)) != null)) 
                    {
                        iDis.Dispose(); 
                    }
                }
            }
 
            return replyMsg;
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink) 
        {
            Message.DebugOut("+++++++++++++++++++++++++ SrvCtxTerminator: SyncProcessMsg");
            IMessageCtrl msgCtrl=null;
            IMessage errMsg = ValidateMessage(reqMsg); 

            if (errMsg == null) 
            { 
                errMsg = DisallowAsyncActivation(reqMsg);
            } 

            if (errMsg != null)
            {
                if (replySink!=null) 
                {
                    replySink.SyncProcessMessage(errMsg); 
                } 
            }
            else 
            {
                // <
                MarshalByRefObject obj;
                IMessageSink nextChain = GetObjectChain(reqMsg, out obj); 
                IDisposable iDis;
                if (obj != null && ((iDis = (obj as IDisposable)) != null)) 
                { 
                    DisposeSink dsink = new DisposeSink(iDis, replySink);
                    replySink = dsink; 
                }
                msgCtrl = nextChain.AsyncProcessMessage(
                                reqMsg,
                                replySink); 

            } 
            return msgCtrl; 
        }
 
        public IMessageSink NextSink
        {
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                // We are the terminal sink of this chain 
                return null; 
            }
        } 

        [System.Security.SecurityCritical]  // auto-generated
        internal virtual IMessageSink GetObjectChain(IMessage reqMsg,out MarshalByRefObject obj)
        { 
            ServerIdentity srvID = GetServerIdentity(reqMsg);
            return srvID.GetServerObjectChain(out obj); 
        } 
    }
 
    internal class DisposeSink : IMessageSink
    {
        IDisposable _iDis;
        IMessageSink _replySink; 
        internal DisposeSink(IDisposable iDis, IMessageSink replySink)
        { 
            _iDis = iDis; 
            _replySink = replySink;
        } 

        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessage SyncProcessMessage(IMessage reqMsg)
        { 
            IMessage replyMsg = null;
            try{ 
                if (_replySink != null) 
                {
                    replyMsg = _replySink.SyncProcessMessage(reqMsg); 
                }
            }
            finally{
                // call dispose on the object now! 
                _iDis.Dispose();
            } 
            return replyMsg; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        {
            throw new NotSupportedException(); 
        }
        public IMessageSink NextSink 
        { 
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                return _replySink;
            }
        } 
    }
 
 
   //
   // Terminator sink for the server object sink chain. This should 
   // be just replaced by the dispatcher sink.
   //

    /* package scope */ 
    [Serializable]
    internal class ServerObjectTerminatorSink : InternalSink, IMessageSink 
    { 
        internal StackBuilderSink _stackBuilderSink;
        internal ServerObjectTerminatorSink(MarshalByRefObject srvObj) 
        {
            _stackBuilderSink = new StackBuilderSink(srvObj);
        }
 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg) 
        {
            Message.DebugOut("+++++++++++++++++++++++++ SrvObjTerminator: SyncProcessMsg\n"); 
            IMessage errMsg = ValidateMessage(reqMsg);
            if (errMsg != null)
            {
                return errMsg; 
            }
 
            ServerIdentity srvID = GetServerIdentity(reqMsg); 

            BCLDebug.Assert(null != srvID,"null != srvID"); 
            ArrayWithSize objectSinks = srvID.ServerSideDynamicSinks;
            if (objectSinks != null)
            {
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                    reqMsg,
                                    objectSinks, 
                                    false,  // bCliSide 
                                    true,   // bStart
                                    false); // bAsync 
            }

            Message.DebugOut("ServerObjectTerminator.Invoking method on object\n");
 
            // Pass call on to the server object specific chain
            BCLDebug.Assert(null != _stackBuilderSink,"null != _stackBuilderSink"); 
 
            IMessage replyMsg;
 
            IMessageSink serverAsSink = _stackBuilderSink.ServerObject as IMessageSink;
            if (serverAsSink != null)
                replyMsg = serverAsSink.SyncProcessMessage(reqMsg);
            else 
                replyMsg = _stackBuilderSink.SyncProcessMessage(reqMsg);
 
            if (objectSinks != null) 
            {
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                    replyMsg,
                                    objectSinks,
                                    false,  // bCliSide
                                    false,  // bStart 
                                    false); // bAsync
            } 
            return replyMsg; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        {
            IMessageCtrl msgCtrl=null; 
            IMessage errMsg = ValidateMessage(reqMsg);
            // < 
 
            if (errMsg!=null)
            { 
                if (replySink!=null)
                {
                    replySink.SyncProcessMessage(errMsg);
                } 
            }
            else 
            { 
                // Pass call on to the server object specific chain
                IMessageSink serverAsSink = _stackBuilderSink.ServerObject as IMessageSink; 
                if (serverAsSink != null)
                    msgCtrl = serverAsSink.AsyncProcessMessage(reqMsg, replySink);
                else
                    msgCtrl = _stackBuilderSink.AsyncProcessMessage(reqMsg, replySink); 
            }
            return msgCtrl; 
        } 

        public IMessageSink NextSink 
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            { 
                // We are the terminal sink of this chain
                return null; 
            } 
        }
 
    }


   // 
   // Terminator sink used for profiling so that we can intercept asynchronous
   // replies on the client side. 
   // 

    /* package scope */ 
    internal class ClientAsyncReplyTerminatorSink : IMessageSink
    {
        internal IMessageSink _nextSink;
 
        internal ClientAsyncReplyTerminatorSink(IMessageSink nextSink)
        { 
            BCLDebug.Assert(nextSink != null, 
                           "null IMessageSink passed to ClientAsyncReplyTerminatorSink ctor.");
            _nextSink = nextSink; 
        }

        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessage SyncProcessMessage(IMessage replyMsg) 
        {
            // If this class has been brought into the picture, then the following must be true. 
            BCLDebug.Assert(RemotingServices.CORProfilerTrackRemoting(), 
                            "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
            BCLDebug.Assert(RemotingServices.CORProfilerTrackRemotingAsync(), 
                            "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");

            Guid g = Guid.Empty;
 
            // If GUID cookies are active, then we try to get it from the properties dictionary
            if (RemotingServices.CORProfilerTrackRemotingCookie()) 
            { 
                Object obj = replyMsg.Properties["CORProfilerCookie"];
 
                if (obj != null)
                {
                    g = (Guid) obj;
                } 
            }
 
            // Notify the profiler that we are receiving an async reply from the server-side 
            RemotingServices.CORProfilerRemotingClientReceivingReply(g, true);
 
            // Now that we've done the intercepting, pass the message on to the regular chain
            return _nextSink.SyncProcessMessage(replyMsg);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage replyMsg, IMessageSink replySink) 
        { 
            // Since this class is only used for intercepting async replies, this function should
            // never get called. (Async replies are synchronous, ironically) 
            BCLDebug.Assert(false, "ClientAsyncReplyTerminatorSink.AsyncProcessMessage called!");

            return null;
        } 

        public IMessageSink NextSink 
        { 
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                return _nextSink;
            }
        } 

        // Do I need a finalize here? 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//
//   Remoting terminator sinks for sink chains along a remoting call. 
//   There is only one static instance of each of these exposed through 
//   the MessageSink property.
// 
namespace System.Runtime.Remoting.Messaging {

    using System;
    using System.Threading; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting.Activation; 
    using System.Runtime.Remoting.Channels; 
    using System.Runtime.Remoting.Contexts;
    using System.Collections; 
    using System.Globalization;
   //   Methods shared by all terminator sinks.
   //
    [Serializable] 
    internal class InternalSink
    { 
        /* 
         *  Checks the replySink param for NULL and type.
         *  If the param is good, it returns NULL. 
         *  Else it returns a Message with the relevant exception.
         */
        [System.Security.SecurityCritical]  // auto-generated
        internal static IMessage ValidateMessage(IMessage reqMsg) 
        {
            IMessage retMsg = null; 
            if (reqMsg == null) 
            {
                retMsg = new ReturnMessage( new ArgumentNullException("reqMsg"), null); 
            }
            return retMsg;
        }
 
        /*
         *  This check is performed only for client & server context 
         *  terminator sinks and only on the Async path. 
         *
         */ 
        [System.Security.SecurityCritical]  // auto-generated
        internal static IMessage DisallowAsyncActivation(IMessage reqMsg)
        {
            // < 

            if (reqMsg is IConstructionCallMessage) 
            { 

                return new ReturnMessage(new RemotingException(Environment.GetResourceString("Remoting_Activation_AsyncUnsupported")), 
                                         null /*reqMsg*/ );
            }
            return null;
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static Identity GetIdentity(IMessage reqMsg) 
        {
            Identity id = null; 

            if (reqMsg is IInternalMessage)
            {
                id = ((IInternalMessage) reqMsg).IdentityObject; 
            }
            else if (reqMsg is InternalMessageWrapper) 
            { 
                id = (Identity)((InternalMessageWrapper)reqMsg).GetIdentityObject();
            } 

            // Try the slow path if the identity has not been obtained yet
            if(null == id)
            { 
                String objURI = GetURI(reqMsg);
 
                id = IdentityHolder.ResolveIdentity(objURI); 

                // An object could get disconnected on another thread while a call is in progress 
                if(id == null)
                {
                    throw new ArgumentException(Environment.GetResourceString("Remoting_ServerObjectNotFound", objURI));
                } 
            }
 
            return id; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static ServerIdentity GetServerIdentity(IMessage reqMsg)
        {
            ServerIdentity srvID = null; 
            bool bOurMsg = false;
            String objURI = null; 
 
            IInternalMessage iim = reqMsg as IInternalMessage;
            if (iim != null) 
            {
                Message.DebugOut("GetServerIdentity.ServerIdentity from IInternalMessage\n");
                srvID = ((IInternalMessage) reqMsg).ServerIdentityObject;
                bOurMsg = true; 
            }
            else if (reqMsg is InternalMessageWrapper) 
            { 
                srvID = (ServerIdentity)((InternalMessageWrapper)reqMsg).GetServerIdentityObject();
            } 

            // Try the slow path if the identity has not been obtained yet
            if(null == srvID)
            { 
                Message.DebugOut("GetServerIdentity.ServerIdentity from IMethodCallMessage\n");
                objURI = GetURI(reqMsg); 
                Identity id = 
                    IdentityHolder.ResolveIdentity(objURI);
                if(id is ServerIdentity) 
                {
                    srvID = (ServerIdentity)id;

                    // Cache the serverIdentity in the message 
                    if (bOurMsg)
                    { 
                        iim.ServerIdentityObject = srvID; 
                    }
                } 
            }

            return srvID;
        } 

        // Retrieve the URI either via a method call or through 
        // a dictionary property. 
        [System.Security.SecurityCritical]  // auto-generated
        internal static String GetURI(IMessage msg) 
        {
            String uri = null;

            IMethodMessage mm = msg as IMethodMessage; 
            if (mm != null)
            { 
                uri = mm.Uri; 
            }
            else 
            {
                IDictionary prop = msg.Properties;
                if(null != prop)
                { 
                    uri = (String)prop["__Uri"];
                } 
            } 

            return uri; 
        }
    }

 
   //
   // Terminator sink for server envoy message sink chain. This delegates 
   // to the client context chain for the call. 
   //
 
    /* package scope */
    [Serializable]
    internal class EnvoyTerminatorSink : InternalSink, IMessageSink
    { 
        private static EnvoyTerminatorSink messageSink;
        private static Object staticSyncObject = new Object(); 
 
        internal static IMessageSink MessageSink
        { 
            get
            {
                if (messageSink == null)
                { 
                    EnvoyTerminatorSink tmpSink = new EnvoyTerminatorSink();
                    lock(staticSyncObject) 
                    { 
                        if (messageSink == null)
                        { 
                            messageSink = tmpSink;
                        }
                    }
                } 
                return messageSink;
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg)
        {
            Message.DebugOut("---------------------------Envoy Chain Terminator: SyncProcessMessage");
            IMessage errMsg = ValidateMessage(reqMsg); 
            if (errMsg != null)
            { 
                return errMsg; 
            }
            // Validate returns null if the reqMsg is okay! 
            return Thread.CurrentContext.GetClientContextChain().SyncProcessMessage(reqMsg);
        }

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        { 
            Message.DebugOut("---------------------------Envoy Chain Terminator: AsyncProcessMessage"); 
            IMessageCtrl msgCtrl = null;
            IMessage errMsg = ValidateMessage(reqMsg); 

            if (errMsg != null)
            {
                // Notify replySink of error if we can 
                // <
 
                if (replySink != null) 
                {
                    replySink.SyncProcessMessage(errMsg); 
                }
            }
            else
            { 
                msgCtrl = Thread.CurrentContext.GetClientContextChain().AsyncProcessMessage(reqMsg, replySink);
            } 
            return msgCtrl; 
        }
 
        public IMessageSink NextSink
        {
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                // We are the terminal sink of this chain 
                return null; 
            }
        } 

    }

 
   //
   // Terminator sink for client context message sink chain. This delegates 
   // to the appropriate channel sink for the call. 
   //
   // 

    /* package scope */
    internal class ClientContextTerminatorSink : InternalSink, IMessageSink
    { 
        private static ClientContextTerminatorSink messageSink;
        private static Object staticSyncObject = new Object(); 
 
        internal static IMessageSink MessageSink
        { 
            get
            {
                if (messageSink == null)
                { 
                    ClientContextTerminatorSink tmpSink = new ClientContextTerminatorSink();
                    lock(staticSyncObject) 
                    { 
                        if (messageSink == null)
                        { 
                            messageSink = tmpSink;
                        }
                    }
                } 
                return messageSink;
            } 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        internal static Object SyncProcessMessageCallback(Object[] args)
        {
            IMessage        reqMsg      = (IMessage) args[0];
            IMessageSink    channelSink = (IMessageSink) args[1]; 

            return channelSink.SyncProcessMessage(reqMsg); 
        } 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg)
        {
            Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: SyncProcessMsg");
            IMessage errMsg = ValidateMessage(reqMsg); 

            if (errMsg != null) 
            { 
                return errMsg;
            } 

            Context ctx = Thread.CurrentContext;

            bool bHasDynamicSinks = 
                ctx.NotifyDynamicSinks(reqMsg,
                        true,   // bCliSide 
                        true,   // bStart 
                        false,  // bAsync
                        true);  // bNotifyGlobals 

            IMessage replyMsg;
            if (reqMsg is IConstructionCallMessage)
            { 
                errMsg = ctx.NotifyActivatorProperties(
                                reqMsg, 
                                false /*bServerSide*/); 
                if (errMsg != null)
                { 
                    return errMsg;
                }

                replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate( 
                                (IConstructionCallMessage)reqMsg);
                BCLDebug.Assert(replyMsg is IConstructionReturnMessage,"bad ctorRetMsg"); 
                errMsg = ctx.NotifyActivatorProperties( 
                                replyMsg,
                                false /*bServerSide*/); 
                if (errMsg != null)
                {
                    return errMsg;
                } 
            }
            else 
            { 
                replyMsg = null;
                ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend); 

                Object[] args = new Object[] { null, null };

                IMessageSink channelSink = GetChannelSink(reqMsg); 

                // Forward call to the channel. 
                args[0] = reqMsg; 
                args[1] = channelSink;
 
                InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback);

                // Move to default context unless we are going through
                // the cross-context channel 
                if (channelSink != CrossContextChannel.MessageSink)
                { 
                    replyMsg = (IMessage) Thread.CurrentThread.InternalCrossContextCallback(Context.DefaultContext, xctxDel, args); 
                }
                else 
                {
                    replyMsg = (IMessage) xctxDel(args);
                }
 
                ChannelServices.NotifyProfiler(replyMsg, RemotingProfilerEvent.ClientReceive);
            } 
 

            if (bHasDynamicSinks) 
            {
                ctx.NotifyDynamicSinks(reqMsg,
                                   true,   // bCliSide
                                   false,  // bStart 
                                   false,  // bAsync
                                   true);  // bNotifyGlobals 
            } 

            return replyMsg; 
        }

        [System.Security.SecurityCritical]  // auto-generated
        internal static Object AsyncProcessMessageCallback(Object[] args) 
        {
            IMessage     reqMsg         = (IMessage) args[0]; 
            IMessageSink replySink      = (IMessageSink) args[1]; 
            IMessageSink channelSink    = (IMessageSink) args[2];
 
            return channelSink.AsyncProcessMessage(reqMsg, replySink);
        }

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        { 
            Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: AsyncProcessMsg"); 
            IMessage errMsg = ValidateMessage(reqMsg);
            IMessageCtrl msgCtrl=null; 
            if (errMsg == null)
            {
                errMsg = DisallowAsyncActivation(reqMsg);
            } 

            if (errMsg != null) 
            { 
                if (replySink != null)
                { 
                    replySink.SyncProcessMessage(errMsg);
                }
            }
            else 
            {
                // If active, notify the profiler that an asynchronous remoting call is being made. 
                if (RemotingServices.CORProfilerTrackRemotingAsync()) 
                {
                    Guid g; 

                    RemotingServices.CORProfilerRemotingClientSendingMessage(out g, true);

                    if (RemotingServices.CORProfilerTrackRemotingCookie()) 
                        reqMsg.Properties["CORProfilerCookie"] = g;
 
                    // Only wrap the replySink if the call wants a reply 
                    if (replySink != null)
                    { 
                        // Now wrap the reply sink in our own so that we can notify the profiler of
                        // when the reply is received.  Upon invocation, it will notify the profiler
                        // then pass control on to the replySink passed in above.
                        IMessageSink profSink = new ClientAsyncReplyTerminatorSink(replySink); 

                        // Replace the reply sink with our own 
                        replySink = profSink; 
                    }
                } 

                Context cliCtx = Thread.CurrentContext;

                // Notify dynamic sinks that an Async call started 
                cliCtx.NotifyDynamicSinks(
                        reqMsg, 
                        true,   // bCliSide 
                        true,   // bStart
                        true,   // bAsync 
                        true);  // bNotifyGlobals

                // Intercept the async reply to force the thread back
                // into the client-context before it executes further 
                // and to notify dynamic sinks
                if (replySink != null) 
                { 
                    replySink = new AsyncReplySink(replySink, cliCtx);
                } 

                Object[]  args = new Object[] { null, null, null };
                InternalCrossContextDelegate    xctxDel = new InternalCrossContextDelegate(AsyncProcessMessageCallback);
 
                IMessageSink channelSink = GetChannelSink(reqMsg);
 
                // Forward call to the channel. 
                args[0] = reqMsg;
                args[1] = replySink; 
                args[2] = channelSink;

                // Move to default context unless we are going through
                // the cross-context channel 
                if (channelSink != CrossContextChannel.MessageSink)
                { 
                    msgCtrl = (IMessageCtrl) Thread.CurrentThread.InternalCrossContextCallback(Context.DefaultContext, xctxDel, args); 
                }
                else 
                {
                    msgCtrl = (IMessageCtrl) xctxDel(args);
                }
            } 
            return msgCtrl;
        } 
 
        public IMessageSink NextSink
        { 
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                // We are the terminal sink of this chain 
                return null;
            } 
        } 

        // Find the next chain (or channel) sink to delegate to. 
        [System.Security.SecurityCritical]  // auto-generated
        private IMessageSink GetChannelSink(IMessage reqMsg)
        {
            Identity id = GetIdentity(reqMsg); 
            return id.ChannelSink;
        } 
    } 

    internal class AsyncReplySink : IMessageSink 
        {

            IMessageSink _replySink;// original reply sink that we are wrapping
            Context _cliCtx;        // the context this call emerged from 

            internal AsyncReplySink(IMessageSink replySink, Context cliCtx) 
            { 
                _replySink = replySink;
                _cliCtx = cliCtx; 
            }

            [System.Security.SecurityCritical]  // auto-generated
            internal static Object SyncProcessMessageCallback(Object[] args) 
            {
                IMessage        reqMsg      = (IMessage) args[0]; 
                IMessageSink    replySink   = (IMessageSink) args[1]; 

                // Call the dynamic sinks to notify that the async call 
                // has completed
                Thread.CurrentContext.NotifyDynamicSinks(
                    reqMsg, // this is the async reply
                    true,   // bCliSide 
                    false,  // bStart
                    true,   // bAsync 
                    true);  // bNotifyGlobals 

                // call the original reply sink now that we have moved 
                // to the correct client context
                return replySink.SyncProcessMessage(reqMsg);
            }
 
            [System.Security.SecurityCritical]  // auto-generated
            public virtual IMessage SyncProcessMessage(IMessage reqMsg) 
            { 
                // we just switch back to the old context before calling
                // the next replySink 
                IMessage retMsg = null;
                if (_replySink != null)
                {
                    Object[] args = new Object[] { reqMsg, _replySink }; 
                    InternalCrossContextDelegate    xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback);
 
                    retMsg = (IMessage) Thread.CurrentThread.InternalCrossContextCallback(_cliCtx, xctxDel, args); 
                }
                return retMsg; 
            }

            [System.Security.SecurityCritical]  // auto-generated
            public virtual IMessageCtrl AsyncProcessMessage( 
                IMessage reqMsg, IMessageSink replySink)
            { 
                throw new NotSupportedException(); 
            }
 
            public IMessageSink NextSink
            {
                [System.Security.SecurityCritical]  // auto-generated
                get 
                {
                    return _replySink; 
                } 
            }
        } 



 
   //
   // Terminator sink for server context message sink chain. This delegates 
   // to the appropriate object sink chain for the call. 
   //
   // 

    /* package scope */
    [Serializable]
    internal class ServerContextTerminatorSink : InternalSink, IMessageSink 
    {
        private static ServerContextTerminatorSink messageSink; 
        private static Object staticSyncObject = new Object(); 

        internal static IMessageSink MessageSink 
        {
            get
            {
                if (messageSink == null) 
                {
                    ServerContextTerminatorSink tmpSink = new ServerContextTerminatorSink(); 
                    lock(staticSyncObject) 
                    {
                        if (messageSink == null) 
                        {
                            messageSink = tmpSink;
                        }
                    } 
                }
                return messageSink; 
            } 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg)
        {
            Message.DebugOut("+++++++++++++++++++++++++ SrvCtxTerminator: SyncProcessMsg"); 
            IMessage errMsg = ValidateMessage(reqMsg);
            if (errMsg != null) 
            { 
                return errMsg;
            } 


            Context ctx = Thread.CurrentContext;
            IMessage replyMsg; 
            if (reqMsg is IConstructionCallMessage)
            { 
                errMsg = ctx.NotifyActivatorProperties( 
                                reqMsg,
                                true /*bServerSide*/); 
                if (errMsg != null)
                {
                    return errMsg;
                } 

                replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate((IConstructionCallMessage)reqMsg); 
                BCLDebug.Assert(replyMsg is IConstructionReturnMessage,"bad ctorRetMsg"); 
                errMsg = ctx.NotifyActivatorProperties(
                                replyMsg, 
                                true /*bServerSide*/);
                if (errMsg != null)
                {
                    return errMsg; 
                }
            } 
            else 
            {
                // Pass call on to the server object specific chain 
                MarshalByRefObject obj = null;
                try{
                    replyMsg = GetObjectChain(reqMsg, out obj).SyncProcessMessage(reqMsg);
                } 
                finally {
                    IDisposable iDis = null; 
                    if (obj != null && ((iDis=(obj as IDisposable)) != null)) 
                    {
                        iDis.Dispose(); 
                    }
                }
            }
 
            return replyMsg;
        } 
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink) 
        {
            Message.DebugOut("+++++++++++++++++++++++++ SrvCtxTerminator: SyncProcessMsg");
            IMessageCtrl msgCtrl=null;
            IMessage errMsg = ValidateMessage(reqMsg); 

            if (errMsg == null) 
            { 
                errMsg = DisallowAsyncActivation(reqMsg);
            } 

            if (errMsg != null)
            {
                if (replySink!=null) 
                {
                    replySink.SyncProcessMessage(errMsg); 
                } 
            }
            else 
            {
                // <
                MarshalByRefObject obj;
                IMessageSink nextChain = GetObjectChain(reqMsg, out obj); 
                IDisposable iDis;
                if (obj != null && ((iDis = (obj as IDisposable)) != null)) 
                { 
                    DisposeSink dsink = new DisposeSink(iDis, replySink);
                    replySink = dsink; 
                }
                msgCtrl = nextChain.AsyncProcessMessage(
                                reqMsg,
                                replySink); 

            } 
            return msgCtrl; 
        }
 
        public IMessageSink NextSink
        {
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                // We are the terminal sink of this chain 
                return null; 
            }
        } 

        [System.Security.SecurityCritical]  // auto-generated
        internal virtual IMessageSink GetObjectChain(IMessage reqMsg,out MarshalByRefObject obj)
        { 
            ServerIdentity srvID = GetServerIdentity(reqMsg);
            return srvID.GetServerObjectChain(out obj); 
        } 
    }
 
    internal class DisposeSink : IMessageSink
    {
        IDisposable _iDis;
        IMessageSink _replySink; 
        internal DisposeSink(IDisposable iDis, IMessageSink replySink)
        { 
            _iDis = iDis; 
            _replySink = replySink;
        } 

        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessage SyncProcessMessage(IMessage reqMsg)
        { 
            IMessage replyMsg = null;
            try{ 
                if (_replySink != null) 
                {
                    replyMsg = _replySink.SyncProcessMessage(reqMsg); 
                }
            }
            finally{
                // call dispose on the object now! 
                _iDis.Dispose();
            } 
            return replyMsg; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        {
            throw new NotSupportedException(); 
        }
        public IMessageSink NextSink 
        { 
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                return _replySink;
            }
        } 
    }
 
 
   //
   // Terminator sink for the server object sink chain. This should 
   // be just replaced by the dispatcher sink.
   //

    /* package scope */ 
    [Serializable]
    internal class ServerObjectTerminatorSink : InternalSink, IMessageSink 
    { 
        internal StackBuilderSink _stackBuilderSink;
        internal ServerObjectTerminatorSink(MarshalByRefObject srvObj) 
        {
            _stackBuilderSink = new StackBuilderSink(srvObj);
        }
 

        [System.Security.SecurityCritical]  // auto-generated 
        public virtual IMessage     SyncProcessMessage(IMessage reqMsg) 
        {
            Message.DebugOut("+++++++++++++++++++++++++ SrvObjTerminator: SyncProcessMsg\n"); 
            IMessage errMsg = ValidateMessage(reqMsg);
            if (errMsg != null)
            {
                return errMsg; 
            }
 
            ServerIdentity srvID = GetServerIdentity(reqMsg); 

            BCLDebug.Assert(null != srvID,"null != srvID"); 
            ArrayWithSize objectSinks = srvID.ServerSideDynamicSinks;
            if (objectSinks != null)
            {
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                    reqMsg,
                                    objectSinks, 
                                    false,  // bCliSide 
                                    true,   // bStart
                                    false); // bAsync 
            }

            Message.DebugOut("ServerObjectTerminator.Invoking method on object\n");
 
            // Pass call on to the server object specific chain
            BCLDebug.Assert(null != _stackBuilderSink,"null != _stackBuilderSink"); 
 
            IMessage replyMsg;
 
            IMessageSink serverAsSink = _stackBuilderSink.ServerObject as IMessageSink;
            if (serverAsSink != null)
                replyMsg = serverAsSink.SyncProcessMessage(reqMsg);
            else 
                replyMsg = _stackBuilderSink.SyncProcessMessage(reqMsg);
 
            if (objectSinks != null) 
            {
                DynamicPropertyHolder.NotifyDynamicSinks( 
                                    replyMsg,
                                    objectSinks,
                                    false,  // bCliSide
                                    false,  // bStart 
                                    false); // bAsync
            } 
            return replyMsg; 
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink)
        {
            IMessageCtrl msgCtrl=null; 
            IMessage errMsg = ValidateMessage(reqMsg);
            // < 
 
            if (errMsg!=null)
            { 
                if (replySink!=null)
                {
                    replySink.SyncProcessMessage(errMsg);
                } 
            }
            else 
            { 
                // Pass call on to the server object specific chain
                IMessageSink serverAsSink = _stackBuilderSink.ServerObject as IMessageSink; 
                if (serverAsSink != null)
                    msgCtrl = serverAsSink.AsyncProcessMessage(reqMsg, replySink);
                else
                    msgCtrl = _stackBuilderSink.AsyncProcessMessage(reqMsg, replySink); 
            }
            return msgCtrl; 
        } 

        public IMessageSink NextSink 
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            { 
                // We are the terminal sink of this chain
                return null; 
            } 
        }
 
    }


   // 
   // Terminator sink used for profiling so that we can intercept asynchronous
   // replies on the client side. 
   // 

    /* package scope */ 
    internal class ClientAsyncReplyTerminatorSink : IMessageSink
    {
        internal IMessageSink _nextSink;
 
        internal ClientAsyncReplyTerminatorSink(IMessageSink nextSink)
        { 
            BCLDebug.Assert(nextSink != null, 
                           "null IMessageSink passed to ClientAsyncReplyTerminatorSink ctor.");
            _nextSink = nextSink; 
        }

        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessage SyncProcessMessage(IMessage replyMsg) 
        {
            // If this class has been brought into the picture, then the following must be true. 
            BCLDebug.Assert(RemotingServices.CORProfilerTrackRemoting(), 
                            "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
            BCLDebug.Assert(RemotingServices.CORProfilerTrackRemotingAsync(), 
                            "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");

            Guid g = Guid.Empty;
 
            // If GUID cookies are active, then we try to get it from the properties dictionary
            if (RemotingServices.CORProfilerTrackRemotingCookie()) 
            { 
                Object obj = replyMsg.Properties["CORProfilerCookie"];
 
                if (obj != null)
                {
                    g = (Guid) obj;
                } 
            }
 
            // Notify the profiler that we are receiving an async reply from the server-side 
            RemotingServices.CORProfilerRemotingClientReceivingReply(g, true);
 
            // Now that we've done the intercepting, pass the message on to the regular chain
            return _nextSink.SyncProcessMessage(replyMsg);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public virtual IMessageCtrl AsyncProcessMessage(IMessage replyMsg, IMessageSink replySink) 
        { 
            // Since this class is only used for intercepting async replies, this function should
            // never get called. (Async replies are synchronous, ironically) 
            BCLDebug.Assert(false, "ClientAsyncReplyTerminatorSink.AsyncProcessMessage called!");

            return null;
        } 

        public IMessageSink NextSink 
        { 
            [System.Security.SecurityCritical]  // auto-generated
            get 
            {
                return _nextSink;
            }
        } 

        // Do I need a finalize here? 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
